﻿using System;
using System.Collections.Generic;
using System.Reflection;
using AzureStorageMapper.TableStorage.Attributes;

namespace AzureStorageMapper.TableStorage.Utils
{
    public class TableUtilities
    {
        public static EntityInfo GetEntityInfo(TableEntity te)
        {
            EntityInfo eInfo = new EntityInfo();
            eInfo.Columns = new Dictionary<TableColumn, object>();

            eInfo.PartitionKey = te.PartitionKey;
            eInfo.RowKey = te.RowKey;

            // get table name
            eInfo.TableName = GetModelName(te.GetType());

            // get columns
            PropertyInfo[] pInfos = te.GetType().GetProperties();

            foreach (var item in pInfos)
            {
                object val;
                TableColumn tc = GetColumnInfo(item, out val, te);
                if (tc != null)
                    eInfo.Columns.Add(tc, val);
            }

            return eInfo;
        }

        public static TableInfo GetTableInfo(Type t)
        {
            if (t == null)
                throw new ArgumentNullException("t");

            if (!t.IsSubclassOf(typeof(TableEntity)))
                throw new NotSupportedException(t.FullName);

            TableInfo info = new TableInfo();
            info.Columns = new List<TableColumn>();

            // get table name
            info.Name = GetModelName(t);

            // get columns
            PropertyInfo[] pInfos = t.GetProperties();

            foreach (var item in pInfos)
            {
                object val;
                TableColumn tc = GetColumnInfo(item, out val);
                if (tc != null)
                    info.Columns.Add(tc);
            }

            return info;
        }

        public static TableColumn GetColumnInfo(PropertyInfo pi, out object value, object target = null)
        {
            Attribute[] ais = Attribute.GetCustomAttributes(pi, true);

            TableColumn tc = null;
            value = null;

            if (ais != null && ais.Length > 0)
            {
                foreach (var item in ais)
                {
                    if (item is TableColumn)
                    {
                        tc = (TableColumn)item;

                        if (string.IsNullOrWhiteSpace(tc.Name))
                            tc.Name = pi.Name;

                        if (tc.ColumnType == null)
                            tc.ColumnType = pi.PropertyType;

                        if (target != null)
                            value = pi.GetValue(target, null);

                        break;
                    }
                }
            }

            return tc;
        }

        private static string GetModelName(Type t)
        {
            string mName = null;

            TableModel tModel = GetTableModelAttribute(t);

            // every model must have TableModel attribute
            if (tModel == null)
                throw new Exception(string.Format("Missing 'TableModel' attribute in {0}", t.FullName));

            if (string.IsNullOrWhiteSpace(tModel.Name))
            {
                mName = t.Name;
            }
            else
            {
                mName = tModel.Name;
            }

            return mName;
        }

        private static TableModel GetTableModelAttribute(Type t)
        {
            Attribute[] atts = Attribute.GetCustomAttributes(t, true);

            if (atts != null && atts.Length > 0)
            {
                foreach (var item in atts)
                {
                    if (item is TableModel)
                        return (TableModel)item;
                }
            }

            return null;
        }
    }
}
